package the.workshop.bu.controller;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.fasterxml.jackson.core.type.TypeReference;
import org.apache.commons.collections4.ListUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import org.wisteria.framework.util.SerializeUtil;
import org.wisteria.framework.util.excel.ExcelUtil;
import org.wisteria.framework.web.APIResult;
import org.wisteria.framework.web.BusinessException;
import org.wisteria.framework.web.QueryResult;
import the.broccoli.auth.UserContext;
import the.workshop.bu.dto.*;
import the.workshop.bu.dto.req.*;
import the.workshop.bu.entity.Customer;
import the.workshop.bu.entity.CustomerTel;
import the.workshop.bu.service.CustomerImpExpService;
import the.workshop.bu.service.ICustomerBizCheckService;
import the.workshop.bu.service.ICustomerService;
import the.workshop.bu.service.ICustomerTelService;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 客户控制器
 *
 * @author lei.liu
 * @since 2020-06-15 08:51:26
 */
@RestController
@RequestMapping("/bu/customer")
public class CustomerController {

    private static final Logger LOGGER = LoggerFactory.getLogger(CustomerController.class);

    @Resource
    private ICustomerService customerService;

    @Resource
    private ICustomerBizCheckService customerBizCheckService;

    @Resource
    private CustomerImpExpService customerImpExpService;

    @Resource
    private ICustomerTelService customerTelService;


    @PostMapping(value = "/add")
    public APIResult add(CustomerAddReq req) {
        customerService.save(req);
        return APIResult.success();
    }

    @PostMapping("/remove")
    public APIResult remove(@RequestParam(value = "ids") List<String> ids) {
        customerService.removeByIds(ids, UserContext.userId(), UserContext.userName());
        return APIResult.success();
    }

    @PostMapping("/modify")
    public APIResult modify(@ModelAttribute CustomerModifyReq req) {
        req.setModifiedId(UserContext.userId());
        req.setModifiedName(UserContext.userName());
        customerService.updateById(req);
        return APIResult.success();
    }

    @GetMapping("/{customerId}")
    public APIResult<CustomerDTO> get(@PathVariable(value = "customerId") Integer customerId) {
        return APIResult.success(customerService.detailById(customerId));
    }

    @GetMapping("/page")
    public APIResult<QueryResult<CustomerDTO>> page(@ModelAttribute CustomerQueryReq req) {
        return APIResult.success(customerService.pageList(req.toCustomerCondition(), req.getPageNum(), req.getPageSize()));
    }

    @PostMapping("/excel")
    public void excel(@ModelAttribute CustomerQueryReq req, HttpServletResponse response) {
        exportExcel(req.toCustomerCondition(), response);
    }

    private void exportExcel(CustomerCondition condition, HttpServletResponse response) {
        condition.setPageNum(null);
        condition.setPageSize(null);
        QueryResult<CustomerDTO> queryResult = customerService.pageList(condition, null, null);
        if (!CollectionUtils.isEmpty(queryResult.getItems())) {
            int size = 1;
            int itemSize = queryResult.getItems().size();
            if (itemSize > 1000) {
                size = size + itemSize / 1000;
            }

            List<CustomerExportExcel> excelList = new ArrayList<>(queryResult.getItems().size());
            CustomerExportExcel excel = null;

            List<List<CustomerDTO>> partitionList = ListUtils.partition(queryResult.getItems(), size);
            for (List<CustomerDTO> customerList : partitionList) {
                List<CustomerTel> telList = customerTelService.list(new LambdaQueryWrapper<CustomerTel>()
                        .in(CustomerTel::getCustomerId, customerList.stream().map(CustomerDTO::getId).collect(Collectors.toList()))
                );

                Map<Integer, List<CustomerTel>> customerTelMap = new HashMap<>();
                if (!CollectionUtils.isEmpty(telList)) {
                    customerTelMap = telList.stream().collect(Collectors.groupingBy(CustomerTel::getCustomerId));
                }

                for (CustomerDTO dto : customerList) {
                    excel = new CustomerExportExcel();
                    BeanUtils.copyProperties(dto, excel);

                    List<CustomerTel> itTelList = customerTelMap.get(dto.getId());

                    if (!CollectionUtils.isEmpty(itTelList)) {
                        String telNumber = null;
//                        itTelList = itTelList.stream().filter(it -> it.getIsInvalid() == null || it.getIsInvalid() == 1).collect(Collectors.toList());
                        if (!CollectionUtils.isEmpty(itTelList)) {
                            telNumber = itTelList.stream().filter(it -> it.getIsLegal() != null && it.getIsLegal() == 1).findAny().orElse(new CustomerTel()).getTelNumber();
                            if (!StringUtils.hasText(telNumber)) {
                                telNumber = itTelList.get(0).getTelNumber();
                            }
                        }
                        excel.setTelNumber(telNumber);
                    }
                    excelList.add(excel);
                }
            }

            try {
                ExcelUtil.exportExcelOutputStream(response, excelList, CustomerExportExcel.class, "客户清单");
            } catch (Exception e) {
                LOGGER.error("客户清单导出失败", e);
                throw BusinessException.withErrorCode("客户清单导出失败");
            }
        }
    }

    @PostMapping("/excel/import")
    public APIResult exportExcel(@RequestParam("file") MultipartFile file) {
        if (file.isEmpty()) {
            throw BusinessException.withErrorCode("无法读取到文件");
        }

        List<CustomerImportExcel> data = null;
        try {
            //data = ExcelUtil.readXls("E:\\\\9.xlsx", CustomerImportExcel.class);
            data = ExcelUtil.readXls(file.getBytes(), CustomerImportExcel.class);
        } catch (Exception e) {
            LOGGER.error("导入客户数据，文件解析异常。", e);
            throw BusinessException.withErrorCode("导入客户数据，文件解析异常");
        }

        if (data.size() > 1000) {
            customerImpExpService.importExcelByAsync(data);
            return APIResult.successWithMessage("正在导入数据，数量太大，请稍后查看");
        }

        customerImpExpService.importExcel(null, data);
        return APIResult.success();
    }

    @PostMapping("/importExcelWithBigData")
    public APIResult importExcelWithBigData(@RequestParam("timeTag") String timeTag, @RequestParam("fileUrl") String fileUrl) {
        if (!StringUtils.hasText(timeTag)) {
            return APIResult.fail("请选择时间标签");
        }
        customerImpExpService.importExcelByAsync(timeTag, fileUrl);
        return APIResult.successWithMessage("数据正在后台导入，请稍后查看");
    }

    @PostMapping("/remark")
    public APIResult remark(Integer id, String remark) {
        Customer customer = new Customer();
        customer.setId(id);
        customer.setRemark(remark);
        customer.setModifiedTime(new Date());
        customer.setCreatedId(UserContext.userId());
        customer.setCreatedName(UserContext.userName());
        customerService.updateById(customer);
        return APIResult.success();
    }

    @PostMapping("/toSales")
    public APIResult toSales(@ModelAttribute CustomerSalesReq req) {
        CustomerSalesDTO dto = req.toCustomerSalesDTO();
        dto.setModifiedId(UserContext.userId());
        dto.setModifiedName(UserContext.userName());
        customerService.updateSalesId(dto);
        return APIResult.success();
    }

    @PostMapping(value = "/toSalesByQuantity", produces = {"application/json", "application/xml"})
    public APIResult toSalesByQuantity(@RequestParam("dataJson") String dataJson) {
        if (StringUtils.hasText(dataJson)) {
            List<SalesQuantityReq> dataList = SerializeUtil.deserialize(dataJson, new TypeReference<List<SalesQuantityReq>>() {
            });
            customerService.updateSalesId(dataList);
        }

        return APIResult.success();
    }

    @PostMapping("/moveStatus")
    public APIResult moveStatus(@ModelAttribute CustomerMoveStatusReq req) {
        customerService.moveStatus(req.toCustomerMoveStatusDTO());
        return APIResult.success();
    }

    @GetMapping("/myCustomer")
    public APIResult myCustomer(@ModelAttribute CustomerQueryReq req) {
        CustomerCondition condition = req.toCustomerCondition();
        condition.setKeyword(req.getKeyword());
        condition.setOrderBy(req.getOrderBy());
        condition.setSalesId(UserContext.userId());
        return APIResult.success(customerService.pageList(condition, req.getPageNum(), req.getPageSize()));
    }

    @PostMapping("/myCustomer/add")
    public APIResult addMyCustomer(CustomerAddReq req) {
        customerService.save(req);
        return APIResult.success();
    }

    @PostMapping("/myCustomer/excel")
    public void myCustomerExcel(@ModelAttribute CustomerQueryReq req, HttpServletResponse response) {
        CustomerCondition condition = req.toCustomerCondition();
        condition.setSalesId(UserContext.userId());
        exportExcel(condition, response);
    }

    @GetMapping("/checkData")
    public APIResult<CheckDataDTO> checkData(@ModelAttribute CheckTelQueryDTO query) {
        return APIResult.success(customerBizCheckService.checkTelData(query));
    }

    @GetMapping("/getUnconfirmedCustomerCount")
    public APIResult<Integer> getUnconfirmedCustomerCount() {
        LambdaQueryWrapper<Customer> queryWrapper = new LambdaQueryWrapper();
        queryWrapper.eq(Customer::getIsDeleted, 0).isNull(Customer::getSalesId);
        return APIResult.success(customerService.count(queryWrapper));
    }

    @GetMapping("/querySalesQuantity")
    public APIResult<QueryResult<List<SalesQuantityDTO>>> querySalesQuantity() {
        List<SalesQuantityDTO> salesQuantityList = customerService.querySalesQuantity();
        return APIResult.success(new QueryResult(salesQuantityList.size(), salesQuantityList));
    }


}